/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.application;

import com.softwarecraftsmen.orogeny.BuildScript;
import com.softwarecraftsmen.orogeny.BuildInstantiater;
import com.softwarecraftsmen.orogeny.application.compilation.BuildScriptCompiler;
import static com.softwarecraftsmen.orogeny.buildLogs.Indentation.RootIndentation;
import com.softwarecraftsmen.orogeny.buildLogs.IndentingBuildLog;
import com.softwarecraftsmen.orogeny.execution.SuccessOrFailure;
import com.softwarecraftsmen.orogeny.execution.BuildExecuter;
import static com.softwarecraftsmen.orogeny.execution.SuccessOrFailure.Failure;
import static com.softwarecraftsmen.orogeny.execution.SuccessOrFailure.Success;
import com.softwarecraftsmen.orogeny.properties.Evaluatable;
import com.softwarecraftsmen.orogeny.properties.PropertyName;
import com.softwarecraftsmen.orogeny.taskNames.TaskName;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import static java.lang.String.format;
import java.util.LinkedHashMap;
import static java.util.Locale.UK;

public class Application
{
	private final File scriptFile;
	private final TaskName taskName;
	private final IndentingBuildLog indentingBuildLog;

	private final BuildScriptCompiler buildScriptCompiler;
	private final BuildScriptLoader buildScriptLoader;
	private final LinkedHashMap<PropertyName, Evaluatable> commandLineProperties;

	public Application(final @NotNull File scriptFile, final @NotNull TaskName taskName, final @NotNull IndentingBuildLog indentingBuildLog, final @NotNull LinkedHashMap<PropertyName, Evaluatable> commandLineProperties)
	{
		this.scriptFile = scriptFile.getAbsoluteFile();
		this.taskName = taskName;
		this.indentingBuildLog = indentingBuildLog;
		this.commandLineProperties = commandLineProperties;
		buildScriptCompiler = new BuildScriptCompiler(scriptFile);
		buildScriptLoader = new BuildScriptLoader(scriptFile);
	}

	public boolean run()
	{
		indentingBuildLog.writeMessage(RootIndentation, format(UK, "Building task(s) '%1$s' in %2$s", taskName, scriptFileName()));
		SuccessOrFailure successOrFailure;
		try
		{
			final ClassLoader compiledClassLoader = buildScriptCompiler.compileJavaCode();
			final Class<? extends BuildScript> script = buildScriptLoader.loadScript(compiledClassLoader);
			final BuildExecuter buildExecuter = new BuildInstantiater(script, scriptFile.getParentFile(), commandLineProperties).instantiate();
			successOrFailure = buildExecuter.execute(taskName, indentingBuildLog);
		}
		catch(IllegalStateException exception)
		{
			final Exception actual;
			if (exception.getCause() != null && exception.getCause() instanceof Exception)
			{
				actual = (Exception)exception.getCause();
			}
			else
			{
				actual = exception;
			}
			final SuccessOrFailure failure = Failure(actual);
			indentingBuildLog.writeMessage(RootIndentation, failure);
			return false;
		}
		indentingBuildLog.writeMessage(RootIndentation, successOrFailure.isFailure() ? Failure(scriptFileName()) : Success);
		return successOrFailure.isSuccess();
	}

	private String scriptFileName() {return scriptFile.toString();}

}
